package ypmits.videoplayer {
	import flash.events.MouseEvent;
	import assets.Playbutton;
	import ypmits.utils.Logger;
	import ypmits.videoplayer.business.VideoStatusType;
	import ypmits.videoplayer.business.vo.CuepointVO;
	import ypmits.videoplayer.business.vo.ImageDataVO;
	import ypmits.videoplayer.business.vo.MetaDataVO;
	import ypmits.videoplayer.business.vo.TextDataVO;
	import ypmits.videoplayer.event.VideoPlayerEvent;
	import ypmits.videoplayer.view.VideoBackground;
	import ypmits.videoplayer.view.VideoBufferDummy;
	import ypmits.videoplayer.view.VideoControlDummy;
	import ypmits.videoplayer.view.VideoPicture;

	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.AsyncErrorEvent;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.filters.GlowFilter;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;

	/**
	 * @author Dave Lenz
	 */
	public class VideoPlayer extends Sprite implements IVideoPlayer {

		protected var videobackground : IVideoBackground;
		protected var videopicture : VideoPicture;
		protected var video : Video;
		protected var bigplaybutton : Sprite;
		protected var buffersprite : IVideoBuffer;
		protected var netconnection : NetConnection;
		protected var customclient : Object;
		protected var logger : Logger;
		protected var controls : VideoControlDummy;
		
		public var WIDTH : Number;
		public var HEIGHT : Number;
		
		public var stream : NetStream;
		public var metadata : MetaDataVO;
		public var buffertime : Number = .1;
		public var autoplay : Boolean = false;
		public var status : String = VideoStatusType.STOPPED;
		public var moviename : String;
		public var url : String;
		public var soundon : Boolean = true;
		
		private var pauseplay : Playbutton;

		
		
		function VideoPlayer( w : Number, h : Number, bgcolor : uint = 0, alpha : Number = 1, smoothing : Boolean = false, deblocking : int = 1 ) 
		{
			WIDTH = w;
			HEIGHT = h;
			
			videobackground = new VideoBackground( w, h, bgcolor, alpha );
			
			video = new Video( w, h );
			video.deblocking = deblocking;
			video.smoothing = smoothing;
			
			videopicture = new VideoPicture( w, h );
			videopicture.addEventListener( Event.COMPLETE, videopictureHandler );
			
			buffersprite = new VideoBufferDummy( );

			netconnection = new NetConnection( );
			netconnection.addEventListener( NetStatusEvent.NET_STATUS, netStatusHandler );
			netconnection.addEventListener( IOErrorEvent.IO_ERROR, errorHandler );
			netconnection.addEventListener( SecurityErrorEvent.SECURITY_ERROR, errorHandler );
			
			customclient = {onCuePoint:onCuePointHandler, onMetaData:onMetaDataHandler, onImageData:onImageDataHandler, onTextData:onTextDataHandler};
			
			logger = new Logger( );
			
			metadata = new MetaDataVO( );

			bigplaybutton = drawBigPlayButton( 40, 40 );
			bigplaybutton.visible = false;
			
			addChild( videobackground as DisplayObject );
			addChild( video );
			addChild( videopicture );
			addChild( buffersprite as DisplayObject );
			addChild( bigplaybutton );
			
			resize( w, h );
		}

		
		
		public function setPicture( url : String ) : void 
		{
			videopicture.url = url;
		}

		
		
		private function videopictureHandler( e : Event ) : void 
		{
			videopicture.show( );
			dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.PICTURE_RECEIVED ) );
		}

		
		
		private function errorHandler( e : * ) : void 
		{
			if( e is IOErrorEvent ) {
				logger.log( IOErrorEvent( e ).text, Logger.ERROR );
			} else if( e is SecurityErrorEvent ) {
				logger.log( SecurityErrorEvent( e ).text, Logger.ERROR );
			} else if( e is AsyncErrorEvent ) {
				logger.log( SecurityErrorEvent( e ).text, Logger.ERROR );
			} else if( e is NetStatusEvent ) {
				logger.log( String( NetStatusEvent( e ).info ), Logger.ERROR );
			}
		}

		
		
		private function onMetaDataHandler( infoobject : Object ) : void 
		{
			metadata = new MetaDataVO( infoobject );
			var e : VideoPlayerEvent = new VideoPlayerEvent( VideoPlayerEvent.METADATA_RECEIVED );
			e.metadatavo = metadata;
			dispatchEvent( e );
		}

		
		
		private function onImageDataHandler( infoobject : Object ) : void 
		{
			var e : VideoPlayerEvent = new VideoPlayerEvent( VideoPlayerEvent.IMAGEDATA_RECEIVED );
			e.imagedatavo = new ImageDataVO( infoobject );
			dispatchEvent( e );
		}

		
		
		private function onTextDataHandler( infoobject : Object ) : void 
		{
			var e : VideoPlayerEvent = new VideoPlayerEvent( VideoPlayerEvent.TEXTDATA_RECEIVED );
			e.textdatavo = new TextDataVO( infoobject );
			dispatchEvent( e );
		}

		
		
		private function onCuePointHandler( infoobject : Object ) : void 
		{
			var e : VideoPlayerEvent = new VideoPlayerEvent( VideoPlayerEvent.CUE_POINT_RECEIVED );
			e.cuepointvo = new CuepointVO( infoobject );
			dispatchEvent( e );
		}

		
		
		public function mute() : void 
		{
			stream.soundTransform = new SoundTransform( 0 );
		}

		
		
		public function resumeAudio() : void 
		{
			stream.soundTransform = new SoundTransform( 1 );
		}

		
		
		public function reset() : void 
		{
			autoplay = false;
		}

		
		
		public function load( name : String = null, url : String = null, autoplay : Boolean = false, buffertime : Number = .1 ) : void 
		{
			close( );
			
			IVideoBuffer( buffersprite ).show();
			this.moviename = name;
			this.url = url;
			this.autoplay = autoplay;
			this.buffertime = buffertime;
			
			if( controls ) controls.controls_title.text = name;
			
			netconnection.connect( null );
		}

		
		
		public function pause() : void 
		{
			if( stream ) {
				status = VideoStatusType.STOPPED;
				stream.pause( );
				removeEventListener( Event.ENTER_FRAME, currentTimeHandler );
				
				dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.PLAY_PAUSE ) );
				
				showBigPlayButton( );
			}
		}

		
		
		private function showBigPlayButton() : void 
		{
			bigplaybutton.visible = true;
		}

		
		
		private function hideBigPlayButton() : void 
		{
			bigplaybutton.visible = false;
		}

		
		
		public function resume() : void 
		{
			if( stream ) {
				status = VideoStatusType.PLAYING;
				stream.resume( );
				addEventListener( Event.ENTER_FRAME, currentTimeHandler );

				dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.PLAY_PAUSE ) );

				hideBigPlayButton( );
			}
		}

		
		
		protected function setControls( controlsprite : Sprite ) : void 
		{
			
			controls = new VideoControlDummy( controlsprite, logger );
			addChild( controls );
			
			updateControlPosition( );
		}

		
		
		private function netStatusHandler( e : NetStatusEvent ) : void 
		{
			trace(e.info['code']);
			logger.log( "netstatusevent.info.code: " + e.info['code'], Logger.NOTIFICATION );
			switch ( e.info['code'] ) {
				
				case "NetConnection.Connect.Success":
					stream = new NetStream( netconnection );
					stream.client = customclient;
					stream.bufferTime = buffertime;
					stream.addEventListener( NetStatusEvent.NET_STATUS, netStatusHandler );
					stream.addEventListener( AsyncErrorEvent.ASYNC_ERROR, errorHandler );
					video.attachNetStream( stream );
					stream.play( url );
					if( !autoplay ) pause( );
					addEventListener( Event.ENTER_FRAME, bufferHandler );
					buffersprite.show( );
					
					if( controls ) controls.reset( );

					hideBigPlayButton( );
					
					break;
				
				case "NetStream.Play.StreamNotFound":
					status = VideoStatusType.STOPPED;
					
					dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.CANNOT_LOCATE_VIDEO ) );
					break;
				
				case "NetStream.Play.Start":
				
					status = VideoStatusType.PLAYING;
					addEventListener( Event.ENTER_FRAME, currentTimeHandler );
					videopicture.hide( );
					
					dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.START_PLAY ) );

					break;
				
				case "NetStream.Play.Stop":
					status = VideoStatusType.STOPPED;
					removeEventListener( Event.ENTER_FRAME, currentTimeHandler );
					
					dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.CLOSE ) );
					break;
			}
			//trace( logger.ttrace() );
		}

		
		
		public function play() : void 
		{
			if( stream ) {
				status = VideoStatusType.PLAYING;
				addEventListener( Event.ENTER_FRAME, currentTimeHandler );
				stream.resume( );
			}
		}

		
		
		public function seekPercentage( percentage : Number ) : void 
		{
			percentage < 0 ? percentage = 0 : percentage = percentage;
			percentage > 100 ? percentage = 100 : percentage = percentage;
			
			if( stream ) stream.seek( percentage * (metadata.duration / 100) );
		}

		
		
		public function seek( time : Number ) : void 
		{
			if( stream ) stream.seek( time );
		}

		
		
		// ============
		//   HANDLERS
		// ============
		private function currentTimeHandler(event : Event) : void 
		{
			var percentageplayed : Number;
			try { 
				percentageplayed = stream.time / (metadata.duration / 100);
				if( metadata && ( !isNaN( percentageplayed ) ) ) metadata.percentagedone = percentageplayed;
				controls.controls_playhead.x = ( controls.controlbar_width / 100 ) * percentageplayed;
				
				controls.controls_pasttime.text = convertNumberToVideoTime( stream.time );
				controls.controls_togotime.text = convertNumberToVideoTime( (metadata.duration - stream.time) );
				
				var e : VideoPlayerEvent = new VideoPlayerEvent( VideoPlayerEvent.CHANGE );
				e.currentTime = stream.time;
				e.percentagePlayed = percentageplayed;
				dispatchEvent( e );
			} catch( e : * ) {
				//trace( "VideoPlayer.currentTimeHandler("+[metadata]+")" );
			}
		}

		
		
		public static function convertNumberToVideoTime( number : Number ) : String 
		{
			var input : Number = Math.round( number );
			var pastminutes : Number = Math.floor( input / 60 );
			var pastminutestext : String = ( pastminutes < 10 ) ? "0" + String( pastminutes ) : String( pastminutes );
			var pasthours : Number = Math.floor( pastminutes / 60 );
			var pasthourstext : String = ( pasthours < 10 ) ? "0" + String( pasthours ) : String( pasthours );
			var pastseconds : Number = Math.floor( input );
			var pastsecondstext : String = ( pastseconds < 10 ) ? "0" + String( pastseconds ) : String( pastseconds );

			return (pasthourstext + ":" + pastminutestext + ":" + pastsecondstext);
		}

		
		
		private function bufferHandler(event : Event) : void 
		{
			var percentageBuffered : int = int( (stream.bytesLoaded / stream.bytesTotal ) * 100 );

			buffersprite.setPercentageBuffered( percentageBuffered );
			if( controls ) controls.controls_bufferbar.scaleX = percentageBuffered / 100;
			
			if( percentageBuffered == 100 ) {
				removeEventListener( Event.ENTER_FRAME, bufferHandler );
				buffersprite.hide( );
			}
		}

		
		
		public function resize( width : Number, height : Number, keepproportions : Boolean = true ) : void 
		{
			WIDTH = width;
			HEIGHT = height;
			
			if( keepproportions ) {
				video.width = WIDTH;
				video.scaleY = video.scaleX;
				if( video.height < HEIGHT ) {
					video.height = HEIGHT;
					video.scaleX = video.scaleY;
				}
				video.x = -((video.width - WIDTH) * .5);
				video.y = -((video.height - HEIGHT) * .5);
			} else {
				video.width = WIDTH;
				video.scaleY = video.scaleX;
			}
			if( status == VideoStatusType.PLAYING ) {
				DisplayObject( buffersprite ).x = Math.round( WIDTH * .5 );
				DisplayObject( buffersprite ).y = Math.round( HEIGHT * .5 );
			}
			
			DisplayObject( videobackground ).width = WIDTH;
			DisplayObject( videobackground ).height = HEIGHT;
			
			bigplaybutton.x = WIDTH * .5;
			bigplaybutton.y = HEIGHT * .5;
			
			if( pauseplay ) {
				pauseplay.x = WIDTH * .5;
				pauseplay.y = HEIGHT * .5;
			}
			
			updateControlPosition( );
		}

		
		
		public function setBufferTime( buffertime : Number = .1 ) : void 
		{
			this.buffertime = buffertime;
		}

		
		
		public function setAutoPlay( autoplay : Boolean = false ) : void 
		{
			this.autoplay = autoplay;
		}

		
		
		public function show() : void 
		{
			dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.FADE_IN_STARTED ) );
		}

		
		
		public function showDone() : void 
		{
			dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.FADE_IN_FINISHED ) );
		}

		
		
		public function hide() : void 
		{
			dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.FADE_OUT_STARTED ) );
		}

		
		
		public function hideDone() : void 
		{
			dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.FADE_OUT_FINISHED ) );
		}

		
		
		public function dispose() : void 
		{
			trace( "VideoPlayer.dispose("+[]+")" );
			video.clear( );
			netconnection.removeEventListener( NetStatusEvent.NET_STATUS, netStatusHandler );
			netconnection.removeEventListener( IOErrorEvent.IO_ERROR, errorHandler );
			netconnection.removeEventListener( SecurityErrorEvent.SECURITY_ERROR, errorHandler );
		}

		
		
		/**
		 * 0: Lets the video compressor apply the deblocking filter as needed.<br>
		 * 1: Does not use a deblocking filter.<br>
		 * 2: Uses the Sorenson deblocking filter.<br>
		 * 3: For On2 video only, uses the On2 deblocking filter but no deringing filter.<br>
		 * 4: For On2 video only, uses the On2 deblocking and deringing filter.<br>
		 * 5: For On2 video only, uses the On2 deblocking and a higher-performance On2 deringing filter.
		 */
		public function set deblocking( deblocking : int ) : void {
			video.deblocking = deblocking;
		}

		
		
		public function set smoothing( smoothing : Boolean ) : void {
			video.smoothing = smoothing;
		}

		
		
		private function drawBigPlayButton( w : Number = 40, h : Number = 40 ) : Sprite 
		{
			bigplaybutton = new Sprite( );
			bigplaybutton.graphics.clear( );
			bigplaybutton.graphics.beginFill( 0xFFFFFF, .85 );
			bigplaybutton.graphics.drawRoundRect( -(w * .5), -(h * .5), w, h, (w * .25), (h * .25) );
			bigplaybutton.graphics.beginFill( 0 );
			bigplaybutton.graphics.moveTo( -(w * .2), -(h * .25) );
			bigplaybutton.graphics.lineTo( (w * .2), 0 );
			bigplaybutton.graphics.lineTo( -(w * .2), (h * .25) );
			bigplaybutton.graphics.lineTo( -(w * .2), -(h * .25) );
			bigplaybutton.graphics.endFill( );
			bigplaybutton.filters = [ new GlowFilter( 0xFFFFFF, .4, 4, 4, 2, 3 ) ];
			bigplaybutton.buttonMode = true;
			bigplaybutton.mouseChildren = false;
			
			return bigplaybutton;
		}

		
		
		public function close() : void 
		{
			if( stream ) {
				stream.seek( 0 );
				stream.close( );
			}
			removeEventListener( Event.ENTER_FRAME, currentTimeHandler );
			removeEventListener( Event.ENTER_FRAME, bufferHandler );
			videopicture.show( );
		}

		
		
		private function updateControlPosition() : void 
		{
			if( controls ) {
				controls.x = ( WIDTH != -1 ) ? WIDTH * .5 : DisplayObject( videobackground ).width * .5;
				controls.y = ( HEIGHT != -1 ) ? HEIGHT - 80 : DisplayObject( videobackground ).height - 80;
			}
		}

		
		
		private function updateBufferSpritePosition() : void 
		{
			if( controls ) {
				controls.x = ( WIDTH != -1 ) ? WIDTH * .5 : DisplayObject( videobackground ).width * .5;
				controls.y = ( HEIGHT != -1 ) ? HEIGHT - 80 : DisplayObject( videobackground ).height - 80;
			}
		}
		
		
		
		public function setBufferSprite( sprite : IVideoBuffer ) : void
		{
			addChildAt( sprite as DisplayObject, getChildIndex( buffersprite as DisplayObject ) );
			buffersprite = sprite;
			updateBufferSpritePosition();
		}
		
		
		
		public function setBackgroundSprite( sprite : IVideoBackground ) : void
		{
			addChildAt( sprite as DisplayObject, getChildIndex( videobackground as DisplayObject ) );
			videobackground = sprite;
		}



		public function setBigPlayButton( _pauseplay : Playbutton ) : void
		{
			pauseplay = _pauseplay;
			pauseplay.buttonMode = true;
			pauseplay.addEventListener( MouseEvent.CLICK, bigPlayClickHandler );
		}



		private function bigPlayClickHandler( e : MouseEvent ) : void
		{
			switch( e.type ) {
				case MouseEvent.CLICK:
					if( pauseplay.currentFrame == 1) {
						pauseplay.gotoAndStop( 2 );
					} else {
						pauseplay.gotoAndStop( 1 );
					}
					break;
			}
		}
	}
}
